import { ModernBaseService } from './base/ModernBaseService';
import { DIContainer } from '../infrastructure/di';
import sdk from '../core';
import { ComType } from '../core/tool/component';
import { ItemType, RankingType } from '../shared/face/enums';
import { RankingItem } from '../shared/face';

export class ModernRankingService extends ModernBaseService {
    private rankingCache: Map<RankingType, RankingItem[]> = new Map();
    private lastSettlementTime: number = 0;
    private readonly SETTLEMENT_INTERVAL = 7 * 24 * 60 * 60 * 1000;
    private readonly SETTLEMENT_HOUR = 3;

    constructor(container?: DIContainer) {
        super(container);
    }

    getServiceName(): string {
        return 'ModernRankingService';
    }

    async init(): Promise<void> {
        try {
            await this.loadRankingData();
            await this.checkSettlement();
        } catch (error) {
            this.log(`ModernRankingService init failed: ${(error as any).message}`, 'error');
        }
    }

    async destroy(): Promise<void> {
        // no-op for now
    }

    async updatePlayerRanking(player: any, type: RankingType, score: number): Promise<void> {
        const baseCom = player.getComponent(ComType.base) as any;
        const rpgCom = player.getComponent(ComType.rpg) as any;
        const bagCom = player.getComponent(ComType.背包) as any;
        const signCom = player.getComponent(ComType.签到) as any;

        if (!baseCom) return;

        let actualScore = score;
        switch (type) {
            case RankingType.等级:
                actualScore = rpgCom ? rpgCom.level : 1;
                break;
            case RankingType.金币:
                actualScore = this.getGoldCount(bagCom);
                break;
            case RankingType.签到:
                actualScore = signCom ? signCom.signCount : 0;
                break;
            case RankingType.战力:
                actualScore = rpgCom ? rpgCom._fighting : 0;
                break;
        }

        const rankingItem: RankingItem = {
            playerId: player.id,
            playerName: baseCom.nickName,
            playerEmoji: baseCom.emoji,
            score: actualScore,
            rank: 0,
            lastUpdateTime: Date.now()
        };

        await this.saveRankingItem(type, rankingItem);
        await this.updateRankingCache(type);
    }

    getRankingData(type: RankingType, limit: number = 100): RankingItem[] {
        const rankingData = this.rankingCache.get(type) || [];
        return rankingData.slice(0, limit);
    }

    getPlayerRank(playerId: string, type: RankingType): number {
        const rankingData = this.rankingCache.get(type) || [];
        const playerRank = rankingData.find(item => item.playerId === playerId);
        return playerRank ? playerRank.rank : -1;
    }

    async manualSettlement(): Promise<void> {
        await this.performSettlement();
    }

    async updateAllPlayersRanking(): Promise<void> {
        const players = sdk.user.getPlayers();
        for (const player of players) {
            await this.updatePlayerRanking(player, RankingType.等级, 0);
            await this.updatePlayerRanking(player, RankingType.金币, 0);
            await this.updatePlayerRanking(player, RankingType.签到, 0);
            await this.updatePlayerRanking(player, RankingType.战力, 0);
        }
    }

    async initializeRankingData(): Promise<void> {
        const players = sdk.user.getPlayers();
        if (players.length > 0) {
            await this.updateAllPlayersRanking();
        }
    }

    // ---------------- private helpers ----------------
    private async loadRankingData(): Promise<void> {
        const rankingData = await sdk.db.find('ranking_data');
        const groupedData = new Map<RankingType, RankingItem[]>();
        rankingData.forEach((item: any) => {
            const type = item.type as RankingType;
            if (!groupedData.has(type)) groupedData.set(type, []);
            groupedData.get(type)!.push({
                playerId: item.playerId,
                playerName: item.playerName,
                playerEmoji: item.playerEmoji,
                score: item.score,
                rank: item.rank,
                lastUpdateTime: item.lastUpdateTime
            });
        });
        this.rankingCache = groupedData;
    }

    private getGoldCount(bagCom: any): number {
        try {
            const goldItem = bagCom?.bag?.find((item: any) => item.type === ItemType.资源 && item.id === '1');
            return goldItem ? goldItem.count : 0;
        } catch {
            return 0;
        }
    }

    private async saveRankingItem(type: RankingType, item: RankingItem): Promise<void> {
        const existingItems = await sdk.db.find('ranking_data', { type, playerId: item.playerId });
        const existingItem = existingItems.length > 0 ? existingItems[0] : null;
        if (existingItem) {
            await sdk.db.update('ranking_data', { type, playerId: item.playerId }, {
                playerName: item.playerName,
                playerEmoji: item.playerEmoji,
                score: item.score,
                lastUpdateTime: item.lastUpdateTime
            });
        } else {
            await sdk.db.insert('ranking_data', {
                type,
                playerId: item.playerId,
                playerName: item.playerName,
                playerEmoji: item.playerEmoji,
                score: item.score,
                rank: 0,
                lastUpdateTime: item.lastUpdateTime
            });
        }
    }

    private async updateRankingCache(type: RankingType): Promise<void> {
        const rankingData = await sdk.db.find('ranking_data', { type });
        const sortedData = rankingData
            .map((item: any) => ({
                playerId: item.playerId,
                playerName: item.playerName,
                playerEmoji: item.playerEmoji,
                score: item.score,
                rank: 0,
                lastUpdateTime: item.lastUpdateTime
            }))
            .sort((a, b) => b.score - a.score);

        sortedData.forEach((item, index) => {
            item.rank = index + 1;
        });

        this.rankingCache.set(type, sortedData);

        for (const item of sortedData) {
            await sdk.db.update('ranking_data', { type, playerId: item.playerId }, { rank: item.rank });
        }
    }

    private async checkSettlement(): Promise<void> {
        const now = Date.now();
        const lastSettlement = this.lastSettlementTime;
        if (lastSettlement === 0) {
            this.lastSettlementTime = now;
            return;
        }
        const timeSinceLastSettlement = now - lastSettlement;
        if (timeSinceLastSettlement >= this.SETTLEMENT_INTERVAL) {
            await this.performSettlement();
        }
    }

    private calculateExpReward(rank: number): number {
        if (rank <= 10) return 1000 - (rank - 1) * 50;
        if (rank <= 50) return 500 - (rank - 11) * 10;
        if (rank <= 100) return 100 - (rank - 51) * 2;
        return 0;
    }

    private getRankingTypeName(type: RankingType): string {
        switch (type) {
            case RankingType.等级: return '等级';
            case RankingType.金币: return '金币';
            case RankingType.签到: return '签到';
            case RankingType.战力: return '战力';
            default: return '未知';
        }
    }

    private async sendCombinedRankingReward(playerData: {
        playerId: string;
        playerName: string;
        rewards: Array<{ type: RankingType; rank: number; expReward: number; }>;
        totalExpReward: number;
    }): Promise<void> {
        const title = '🏆排行榜结算奖励';
        let content = `恭喜你在本周排行榜结算中获得奖励！\n\n`;
        for (const reward of playerData.rewards) {
            const typeName = this.getRankingTypeName(reward.type);
            content += `📊${typeName}排行榜：第${reward.rank}名\n`;
        }
        content += `\n🎁奖励已通过附件发放，请注意查收！`;
        const expItem = sdk.prop.createProp({ type: ItemType.资源, id: '经验值', count: playerData.totalExpReward });
        await sdk.mail.send('admin', playerData.playerId, 30, title, content, [expItem]);
    }

    private async performSettlement(): Promise<void> {
        const levelRanking = this.getRankingData(RankingType.等级, 100);
        const goldRanking = this.getRankingData(RankingType.金币, 100);
        const signRanking = this.getRankingData(RankingType.签到, 100);
        const powerRanking = this.getRankingData(RankingType.战力, 100);

        const playerRewards = new Map<string, { playerId: string; playerName: string; rewards: Array<{ type: RankingType; rank: number; expReward: number; }>; totalExpReward: number; }>();

        const accumulate = (list: RankingItem[], type: RankingType) => {
            for (const player of list) {
                if (player && player.rank <= 100) {
                    const expReward = this.calculateExpReward(player.rank);
                    if (expReward > 0) {
                        if (!playerRewards.has(player.playerId)) {
                            playerRewards.set(player.playerId, { playerId: player.playerId, playerName: player.playerName, rewards: [], totalExpReward: 0 });
                        }
                        const data = playerRewards.get(player.playerId)!;
                        data.rewards.push({ type, rank: player.rank, expReward });
                        data.totalExpReward += expReward;
                    }
                }
            }
        };

        accumulate(levelRanking, RankingType.等级);
        accumulate(goldRanking, RankingType.金币);
        accumulate(signRanking, RankingType.签到);
        accumulate(powerRanking, RankingType.战力);

        for (const data of playerRewards.values()) {
            if (data.totalExpReward > 0) {
                await this.sendCombinedRankingReward(data);
            }
        }

        this.lastSettlementTime = Date.now();
        await sdk.db.update('system_config', { key: 'last_ranking_settlement' }, { value: this.lastSettlementTime });
    }
}


